#ifndef APIMOD_H_
#define APIMOD_H_

/*
Copyright (C) 2011 Salil Bhagurkar

This file is part of illusion

illusion is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

illusion is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with illusion.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <kernel/syscall.h>
#include <klib/format.h>


#define		PR_LJ	0x01	/* left justify */
#define		PR_CA	0x02	/* use A-F instead of a-f for hex */
#define		PR_SG	0x04	/* signed numeric conversion (%d vs. %u) */
#define		PR_32	0x08	/* long (32-bit) numeric conversion */
#define		PR_16	0x10	/* short (16-bit) numeric conversion */
#define		PR_WS	0x20	/* PR_SG set and num was < 0 */
#define		PR_LZ	0x40	/* pad left with '0' instead of ' ' */
#define		PR_FP	0x80	/* pointers are far */
#define		PR_BUFLEN	16

#define INI_NAME_LEN 256
#define INI_VALUE_LEN 256

struct ini_setting {
	char name[INI_NAME_LEN];
	char value[INI_NAME_LEN];
	struct ini_setting *next, *prev;
};

struct ini_class {
	char name[INI_NAME_LEN];
	uint_t setting_count;
	struct ini_setting *settings, *settings_tail;
	struct ini_class *prev, *next;
};

struct ini_config {
	uint_t class_count;
	struct ini_class *classes, *classes_tail;
};

#define ARG_LEN 32

#define ARGTYPE_INT 0
#define ARGTYPE_STRING 1

struct argument {
	char name[ARG_LEN];
	//The total bytes occupied by this value
	//Value gets assigned when the argument is passed to the program
	uint_t type;
	uint_t value_len;
	union {
		int_t int_value;
		char string_value[ARG_LEN];
	}value;
	char is_required, requires_value;
	struct argument *next, *prev;
};

struct app_arguments {
	struct argument *args, *args_tail;
};


#define STRING_BASE_CAPACITY 8
#define STRING_MAX_CAPACITY 4096

typedef struct _string {
	uint_t length;			//The number of characters actually present in the
							//string. This includes a null char to allow
							//printfing the string
	uint_t capacity;			//The number of bytes allocated for the string
	char *value;			//The string
}string;


/*
 * The following declarations are for APIMOD internal use.
 * They are obviously not callable either from the kernel or
 * from the user land, but are mostly exposed to the user land
 * through the interfaces defined above.
 */

int vsnprintf(char *to,uint_t sz,const char *fmt, va_list args);
int snprintf(char *buf,uint_t sz,const char *fmt, ...);

uint_t string_length(const char *c);
bool string_equals(const char *s1, const char *s2);
char *string_copy(char *dest, const char *src, uint_t max_len);

void *memory_set(void *start, u8 value, uint_t count);
void *memory_copy(void *dst, void *src, uint_t count);
int get_version(uint_t *build_number,
			uint_t *build_date);
int exit_process();
int release(uint_t reason);
int print(char *stream, uint_t length);
int read_input(uint_t *key, uint_t *state);
int open(char *path, uint_t state, uint_t *fd);
int change_state(uint_t fid, uint_t new_state);
int get_child(uint_t fid, uint_t *child_fid);
int next_child(uint_t fid);
int find_child(uint_t fid, uint_t *child_fid, char *name);
int close(uint_t fid);
int read(uint_t fid, void *buf, uint_t offset,
		uint_t count);
int write(uint_t fid, void *buf, uint_t offset,
		uint_t count);
 int create(uint_t fid, char *name);
 int delete(uint_t fid, uint_t parent_fid);
int get_info(uint_t fid, struct sys_info *info);
int start_process(uint_t *pid, uint_t fid, char *arguments);
int pause_process(uint_t pid);
int resume_process(uint_t pid);
int printf(const char *fmt, ...);
void *sbrk(signed bytes);
void *malloc(uint_t bytes);
void free(void *p, uint_t bytes);
void read_line(char *buf, uint_t buf_len);
char *separate(char *out, char *_str, char delimiter);
int string_starts_with(char *str, char *with);
int string_ends_with(char *str, char *with);
char *string_cat(char *dst, uint_t dst_buf_len, char *src);
char *string_replace(char *out, size_t out_len, char *str, char *what, char *with);
void string_to_lower(char *src);
void string_to_higher(char *src);

int ini_read(struct ini_config **config_ret, char *file_name);
int ini_dispose(struct ini_config *config);
char *ini_get_value(struct ini_config *config, char *path);
struct ini_class *ini_get_class(struct ini_config *config, char *name);

char *get_arguments(uint_t *len);

void add_argument(struct app_arguments *appargs, char *name,
		uint_t type, char is_required, char accepts_value);
int parse_arguments(struct app_arguments *appargs, char *str);

int get_device(uint_t *fid);
int next_device(uint_t fid);

void *get_pages(uint_t count);
int free_pages(void *pages, uint_t count);

uint_t dec_string(char *_str);
uint_t hex_string(char *_str);


void string_init(string *str);
void string_append_char(string *str, char c);
void string_append(string *str, const char *cstring);
void string_init_from(string *str, const char *cstring);
string *string_new();
void string_deinit(string *str);
void string_delete(string *str);

int try();
int exit_try();


/*
 * Function used by APIMOD internally to print a message on fatal errors
 * and exit the current process
 */
int insane(int code, const char *fmt, ...);

/*
 * This file defines the interface provided by apimod to the kernel and user mode.
 */
struct apimod_export {
	//This function is called by the user application: The address is known
	//to the kernel, and is provided to the user mode through a system call
	int (*get_interface)(char *name, void **interface);
};


/*
 * API provided to applications by APIMOD
 */

struct apimod_base {
	int (*try)();
	int (*exit_try)();
	int (*foo)();
	int (*foo_enter)();
	int (*foo_leave)();
	int (*get_version)(uint_t *build_number,
			uint_t *build_date);
	int (*exit_process)();
	int (*release)(uint_t reason);
	int (*create_process)(uint_t *pid, char *path, char *arguments);
	int (*get_current)(uint_t *fid);
	int (*set_current)(uint_t fid);
	char *(*get_arguments)(uint_t *len);
	int (*resume_process)(uint_t pid);
	int (*pause_process)(uint_t pid);
	void *(*get_pages)(uint_t count);
	int (*free_pages)(void *pages, uint_t count);
	int (*wait_for_process)(uint_t pid);
	int (*kill_process)(uint_t pid);
	int (*redirect_out)(uint_t pid, uint_t fid);
};

struct apimod_console {
	int (*printf)(const char *fmt, ...);
	int (*print)(char *stream, uint_t length);
	int (*read_input)(uint_t *key, uint_t *state);
	void (*read_line)(char *buf, uint_t buf_len);
};

struct apimod_lib_string {
	uint_t (*length)(const char *str);
	bool (*equals)(const char *s1, const char *s2);
	char *(*copy)(char *dest, const char *src, uint_t max_len);
	char *(*separate)(char *out, char *_str, char delimiter);
	char *(*cat)(char *dst, uint_t dst_buf_len, char *src);
	int (*starts_with)(char *str, char *with);
	int (*ends_with)(char *str, char *with);
	char *(*replace)(char *out, size_t out_len, char *str, char *what, char *with);
	int (*vsnprintf)(char *to, uint_t sz, const char *fmt, va_list args);
	int (*snprintf)(char *buf,uint_t sz, const char *fmt, ...);
	void (*to_lower)(char *src);
	void (*to_higher)(char *src);
	uint_t (*dec_string)(char *_str);
	uint_t (*hex_string)(char *_str);
};

struct apimod_lib_memory {
	void *(*set)(void *start, u8 value, uint_t count);
	void *(*copy)(void *dst, void *src, uint_t count);
	void *(*malloc)(uint_t bytes);
	void (*free)(void *p, uint_t bytes);
	bool (*equals)(void *m1, void *m2, uint_t count);
};

struct apimod_fs {
	int (*open)(char *path, uint_t state, uint_t *fd);
	int (*close)(uint_t fid);
	int (*change_state)(uint_t fid, uint_t new_state);
	int (*read)(uint_t fid, void *buf, uint_t offset,
			uint_t count);
	int (*readstream)(uint_t fid, char *stream, void *buf,
			uint_t offset, uint_t count);
	int (*write)(uint_t fid, void *buf, uint_t offset,
			uint_t count);
	int (*writestream)(uint_t fid, char *stream, void *buf,
			uint_t offset, uint_t count);
	int (*get_child)(uint_t fid, uint_t *child_fid);
	int (*next_child)(uint_t fid);
	int (*find_child)(uint_t fid, uint_t *child_fid, char *name);
	int (*get_parent)(uint_t fid, uint_t *parent_fid);
	int (*get_info)(uint_t fid, struct sys_info *info);
	int (*get_info1)(uint_t fid, struct sys_info1 *info);
	int (*create)(uint_t fid, char *name);
	int (*delete)(uint_t fid, uint_t parent_fid);
	int (*get_device)(uint_t *fid);
	int (*next_device)(uint_t fid);
};

struct apimod_fs1 {
	char **(*get_children)(char *path, uint_t *nr_children);
	void (*free_children)(char **arr, uint_t nr_children);
	char *(*read_all_file)(uint_t *length, char *path);
	int (*write_all_file)(char *path, char *data, uint_t length);
	int (*create_file)(char *path, char *name);
	int (*delete_file)(char *path);
};


struct apimod_ini {
	int (*read)(struct ini_config **config_ret, char *file_name);
	int (*dispose)(struct ini_config *config);
	char *(*get_value)(struct ini_config *config, char *path);
	struct ini_class *(*get_class)(struct ini_config *config, char *name);
};

struct apimod_args {
	void (*add)(struct app_arguments *appargs, char *name,
		uint_t type, char is_required, char accepts_value);
	int (*parse)(struct app_arguments *appargs, char *str);
};

struct apimod_string {
	void (*init)(string *str);
	void (*append_char)(string *str, char c);
	void (*append)(string *str, const char *cstring);
	void (*init_from)(string *str, const char *cstring);
	string *(*new)();
	void (*deinit)(string *str);
	void (*delete)(string *str);
};

/*
 * Syscall function of the kernel (defined in apimod/amload.s)
 */
extern int _syscall(uint_t no, u32 param0, u32 param1, u32 param2,
		u32 param3, u32 param4);

#endif /* APIMOD_H_ */
